package com.tianji.learning.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.autoconfigure.mq.RabbitMqHelper;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.AssertUtils;
import com.tianji.common.utils.BooleanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.learning.utils.LearningRecordDelayTask;
import groovyjarjarasm.asm.Handle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import static com.tianji.common.constants.MqConstants.Exchange.LEARNING_EXCHANGE;
import static com.tianji.common.constants.MqConstants.Key.LEARN_SECTION;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author hc
 * @since 2024-08-22
 */
@Service
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {

    @Autowired
    private ILearningLessonService lessonService;

    @Autowired
    private CourseClient courseClient;

    @Autowired
    private LearningRecordDelayTask delayTask;

    @Autowired
    private RabbitMqHelper mqHelper;

    /**
     * 查询当前用户指定课程的学习进度
     *
     * @param courseId 课程id
     * @return 课表信息、学习记录及进度信息
     */
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {
        //1、获取用户的id
        Long userId = UserContext.getUser();

        //2、查询用户课表
        LambdaQueryWrapper<LearningLesson> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId);
        LearningLesson lesson = lessonService.getOne(queryWrapper);

        if (ObjectUtil.isEmpty(lesson) || ObjectUtil.equals(lesson.getStatus(), LessonStatus.EXPIRED)) {
            return null;
        }

        //3、根据课表id查询学习记录
        List<LearningRecord> records = lambdaQuery().eq(LearningRecord::getLessonId, lesson.getId()).list();

        //4、封装结果
        return LearningLessonDTO.of(lesson.getId(), lesson.getLatestSectionId(), BeanUtil.copyToList(records, LearningRecordDTO.class));
    }

    /**
     * 提交学习记录
     *
     * @param learningRecordFormDTO
     */
    @Override
    @Transactional
    public void saveLearningRecord(LearningRecordFormDTO learningRecordFormDTO) {
        //1、判断是否是提交的考试的记录
        //1.1、获取是否是第一次学完的状态值
        boolean firstFinished = learningRecordFormDTO.getSectionType() == SectionType.VIDEO ? videoRecord(learningRecordFormDTO) : testRecord(learningRecordFormDTO);

        //1.2、判断是否不是第一次学习完，且是否不是考试类型且duration==-1,如果是不用更新课程，直接更新redis中的记录
        if (!firstFinished && learningRecordFormDTO.getSectionType().equals(SectionType.EXAM) && learningRecordFormDTO.getDuration() == -1) {
            return;
        }

        //2、进行课表的更新
        HandleLearningLesson(learningRecordFormDTO, firstFinished);


    }


    /**
     * 考试记录的添加
     *
     * @param learningRecordFormDTO
     * @return 是否是第一次学完
     */
    private boolean testRecord(LearningRecordFormDTO learningRecordFormDTO) {
        //1、添加考试的学习记录
        LearningRecord learningRecord = BeanUtil.toBean(learningRecordFormDTO, LearningRecord.class);

        learningRecord.setUserId(UserContext.getUser());
        learningRecord.setFinished(true);
        learningRecord.setFinishTime(learningRecordFormDTO.getCommitTime());

        boolean save = save(learningRecord);
        if (!save) {
            throw new DbException("添加学习进度失败!");
        }

        //2、判断是否是第一次提交
        LearningRecord record = lambdaQuery()
                .eq(LearningRecord::getLessonId, learningRecordFormDTO.getLessonId())
                .eq(LearningRecord::getSectionId, learningRecordFormDTO.getSectionId())
                .one();

        if (ObjectUtil.isNotEmpty(record)) {
            return false;
        }

        return true;
    }

    /**
     * 视频学习记录的添加
     *
     * @param learningRecordFormDTO
     * @return 是否是第一次学完
     */
    private boolean videoRecord(LearningRecordFormDTO learningRecordFormDTO) {
        //1、去redis中查询数据，判断记录是否已经存在。
        LearningRecord oldRecord = delayTask.readLearningRecordCache(learningRecordFormDTO);

        if (ObjectUtil.isEmpty(oldRecord)) {
            //2、记录不存在进行新增操作
            LearningRecord newRecord = BeanUtil.toBean(learningRecordFormDTO, LearningRecord.class);
            newRecord.setUserId(UserContext.getUser());

            boolean save = save(newRecord);
            if (!save) {
                throw new DbException("添加学习进度失败!");
            }

            //2.1、往redis缓存中写入数据
            delayTask.writeLearningRecordCache(newRecord);

            return false;
        }

        //3、记录存在进行更新学习记录操作
        //3.1、判断是否第一次学完
        boolean isFirstFinished = !BooleanUtils.isTrue(oldRecord.getFinished()) && learningRecordFormDTO.getMoment() * 2 >= learningRecordFormDTO.getDuration();

        if(isFirstFinished){
            boolean update = lambdaUpdate()
                    .set(LearningRecord::getMoment, learningRecordFormDTO.getMoment())
                    .set(LearningRecord::getFinished, true)
                    .set(LearningRecord::getFinishTime, learningRecordFormDTO.getCommitTime())
                    .eq(LearningRecord::getId, oldRecord.getId())
                    .update();
            if (!update) {
                throw new DbException("更新学习进度失败!");
            }

            //3.2、清除redis缓存
            delayTask.cleanLearningRecordCache(oldRecord);
        }else {

            //3.3、如果不是第一学完，则更新redis缓存
            oldRecord.setMoment(learningRecordFormDTO.getMoment());
            delayTask.writeLearningRecordCache(oldRecord);
        }


        return isFirstFinished;
    }


    /**
     * 进行课表的更新
     *
     * @param learningRecordFormDTO
     * @param firstFinished         是否是第一次更新
     */
    private void HandleLearningLesson(LearningRecordFormDTO learningRecordFormDTO, boolean firstFinished) {
        //1、查询课表，获取课表信息
        LearningLesson learningLesson = lessonService.lambdaQuery()
                .eq(LearningLesson::getId, learningRecordFormDTO.getLessonId())
                .one();

        //2、判断是否是第一次学完
        if (!firstFinished) {
            //2.1、不是第一次学完
            boolean update = lessonService.lambdaUpdate()
                    .set(LearningLesson::getLatestSectionId, learningRecordFormDTO.getSectionId())
                    .set(LearningLesson::getLatestLearnTime, learningRecordFormDTO.getCommitTime())
                    .set(learningLesson.getStatus().equals(LessonStatus.NOT_BEGIN.getValue()), LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                    .eq(LearningLesson::getId, learningRecordFormDTO.getLessonId())
                    .update();

            if (!update) {
                throw new DbException("更新课表数据失败！");
            }
        }

        //3、判断是否学完全部小结
        //3.1、查出该课程总小结数量
        CourseFullInfoDTO courseInfo = courseClient.getCourseInfoById(learningLesson.getCourseId(), false, false);

        //3.2、开始更新
        boolean update = lessonService.lambdaUpdate()
                .set(LearningLesson::getLatestSectionId, learningRecordFormDTO.getSectionId())
                .set(LearningLesson::getLatestLearnTime, learningRecordFormDTO.getCommitTime())
                .set(firstFinished, LearningLesson::getLearnedSections, learningLesson.getLearnedSections() + 1)
                .set(learningLesson.getStatus().equals(LessonStatus.NOT_BEGIN.getValue()), LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .set(learningLesson.getLearnedSections() + 1 >= courseInfo.getSectionNum(), LearningLesson::getStatus, LessonStatus.FINISHED.getValue())
                .eq(LearningLesson::getId, learningRecordFormDTO.getLessonId())
                .update();

        if (!update) {
            throw new DbException("更新课表数据失败！");
        }

        //4、发送消息增加积分
        if(firstFinished){

            mqHelper.send(LEARNING_EXCHANGE,LEARN_SECTION,UserContext.getUser());
        }
    }

}
